//========================================================================
//Copyright 2007-2010 David Yu dyuproject@gmail.com
//------------------------------------------------------------------------
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at 
//http://www.apache.org/licenses/LICENSE-2.0
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//========================================================================

/*
 * Copyright (c) 2009 Jens Scheffler (appenginefan.com)
 * 
 * Licensed under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the
 * License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in
 * writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See
 * the License for the specific language governing
 * permissions and limitations under the License.
 */

package com.dyuproject.kvstore;

import java.util.List;
import java.util.Map.Entry;

/**
 * A set of useful static utility functions for range queries.
 */
public final class Utilities
{

    private Utilities() {}

    /**
     * Finds zero or more entries that start with a given prefix
     * 
     * @param prefix
     *            a string that all keys found should start with.
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @param serializer
     *            the serializer to use.
     * @return a list of up to max key/value pairs, ordered by key
     */
    public static <T> List<Entry<String, T>> scanEntriesByPrefix(Store<T> store, String prefix, 
            int max, Serializer<T> serializer)
    {
        return store.scanEntries(prefix, prefix + Character.MAX_VALUE, max, serializer);
    }

    /**
     * Finds zero or more entries that are within a given range, with the start
     * also being exclusive.
     * 
     * @param start
     *            a lower bound of the range of keys to look in
     *            (<b>exclusive</b>)
     * @param end
     *            an upper bound of the range of keys to look in (exclusive)
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @param serializer
     *            the serializer to use.
     * @return a list of up to max key/value pairs, ordered by key
     */
    public static <T> List<Entry<String, T>> scanEntriesExclusive(Store<T> store, String start, 
            String end, int max, Serializer<T> serializer)
    {
        return store.scanEntries(start + Character.MIN_VALUE, end, max, serializer);
    }

    /**
     * Finds zero or more entries that start with a given prefix. Uses a reverse
     * scan.
     * 
     * @param prefix
     *            a string that all keys found should start with.
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @param serializer
     *            the serializer to use.
     * @return a list of up to max key/value pairs, ordered by key (descending)
     */
    public static <T> List<Entry<String, T>> scanEntriesReverseByPrefix(Store<T> store, 
            String prefix, int max, Serializer<T> serializer)
    {
        return store.scanEntriesReverse(prefix, prefix + Character.MAX_VALUE, max, serializer);
    }

    /**
     * Finds zero or more entries that are within a given range, with the start
     * also being exclusive. Uses a reverse scan.
     * 
     * @param start
     *            a lower bound of the range of keys to look in
     *            (<b>exclusive</b>)
     * @param end
     *            an upper bound of the range of keys to look in (exclusive)
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @param serializer
     *            the serializer to use.
     * @return a list of up to max key/value pairs, ordered by key (descending)
     */
    public static <T> List<Entry<String, T>> scanEntriesReverseExclusive(Store<T> store, 
            String start, String end, int max, Serializer<T> serializer)
    {
        return store.scanEntriesReverse(start + Character.MIN_VALUE, end, max, serializer);
    }
    
    /**
     * Finds zero or more entries that start with a given prefix
     * 
     * @param prefix
     *            a string that all keys found should start with.
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @param serializer
     *            the serializer to use.
     * @return a list of up to max values, ordered by key
     */
    public static <T> List<T> scanByPrefix(Store<T> store, String prefix, int max, 
            Serializer<T> serializer)
    {
        return store.scan(prefix, prefix + Character.MAX_VALUE, max, serializer);
    }

    /**
     * Finds zero or more entries that are within a given range, with the start
     * also being exclusive.
     * 
     * @param start
     *            a lower bound of the range of keys to look in
     *            (<b>exclusive</b>)
     * @param end
     *            an upper bound of the range of keys to look in (exclusive)
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @param serializer
     *            the serializer to use.
     * @return a list of up to max values, ordered by key
     */
    public static <T> List<T> scanExclusive(Store<T> store, String start, String end, 
            int max, Serializer<T> serializer)
    {
        return store.scan(start + Character.MIN_VALUE, end, max, serializer);
    }

    /**
     * Finds zero or more entries that start with a given prefix. Uses a reverse
     * scan.
     * 
     * @param prefix
     *            a string that all keys found should start with.
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @param serializer
     *            the serializer to use.
     * @return a list of up to max values, ordered by key (descending)
     */
    public static <T> List<T> scanReverseByPrefix(Store<T> store, String prefix, 
            int max, Serializer<T> serializer)
    {
        return store.scanReverse(prefix, prefix + Character.MAX_VALUE, max, serializer);
    }

    /**
     * Finds zero or more entries that are within a given range, with the start
     * also being exclusive. Uses a reverse scan.
     * 
     * @param start
     *            a lower bound of the range of keys to look in
     *            (<b>exclusive</b>)
     * @param end
     *            an upper bound of the range of keys to look in (exclusive)
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @param serializer
     *            the serializer to use.
     * @return a list of up to max values, ordered by key (descending)
     */
    public static <T> List<T> scanReverseExclusive(Store<T> store, String start, 
            String end, int max, Serializer<T> serializer)
    {
        return store.scanReverse(start + Character.MIN_VALUE, end, max, serializer);
    }
    
    /**
     * Finds zero or more entries that start with a given prefix
     * 
     * @param prefix
     *            a string that all keys found should start with.
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @return a list of up to max keys, ordered by key
     */
    public static <T> List<String> keyScanByPrefix(Store<T> store, String prefix, int max)
    {
        return store.keyScan(prefix, prefix + Character.MAX_VALUE, max);
    }

    /**
     * Finds zero or more entries that are within a given range, with the start
     * also being exclusive.
     * 
     * @param start
     *            a lower bound of the range of keys to look in
     *            (<b>exclusive</b>)
     * @param end
     *            an upper bound of the range of keys to look in (exclusive)
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @return a list of up to max keys, ordered by key
     */
    public static <T> List<String> keyScanExclusive(Store<T> store, String start, 
            String end, int max)
    {
        return store.keyScan(start + Character.MIN_VALUE, end, max);
    }

    /**
     * Finds zero or more entries that start with a given prefix. Uses a reverse
     * scan.
     * 
     * @param prefix
     *            a string that all keys found should start with.
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @return a list of up to max keys, ordered by key (descending)
     */
    public static <T> List<String> keyScanReverseByPrefix(Store<T> store, String prefix, 
            int max)
    {
        return store.keyScanReverse(prefix, prefix + Character.MAX_VALUE, max);
    }

    /**
     * Finds zero or more entries that are within a given range, with the start
     * also being exclusive. Uses a reverse scan.
     * 
     * @param start
     *            a lower bound of the range of keys to look in
     *            (<b>exclusive</b>)
     * @param end
     *            an upper bound of the range of keys to look in (exclusive)
     * @param max
     *            a maximum amount of elements to return. The implementation of
     *            the store may choose to return less (for example, if a store
     *            can only fetch 10 elements per query, then setting a max of
     *            1000 will still only return 10), but never more.
     * @return a list of up to max keys, ordered by key (descending)
     */
    public static <T> List<String> keyScanReverseExclusive(Store<T> store, String start, 
            String end, int max)
    {
        return store.keyScanReverse(start + Character.MIN_VALUE, end, max);
    }
}
